package com.yonyou.pmclouds.offline.controller;

import com.alibaba.dubbo.config.annotation.Reference;
import com.yonyou.pmclouds.ApplicationConsts;
import com.yonyou.pmclouds.basecom.exception.BusinessException;
import com.yonyou.pmclouds.basecom.runtime.RuntimeEnvironment;
import com.yonyou.pmclouds.offline.aspect.Offline;
import com.yonyou.pmclouds.offline.configuration.OffLineDataExtendLoader;
import com.yonyou.pmclouds.offline.entity.OffLineInvocationContext;
import com.yonyou.pmclouds.offline.rmiitf.IOffLineDataDownloadService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * 离线下载接口
 */
@Slf4j
@RestController
@RequestMapping({"/mobile/offline", "/offline"})
public class OffLineDataDownloadController {

    @Reference(version = ApplicationConsts.APPLICATION_VERSION)
    private IOffLineDataDownloadService downloadService;

    @Autowired
    private OffLineDataExtendLoader extendLoader;

    private final String OFFLINE_OPERATION_BEFORE = "before";

    private final String OFFLINE_OPERATION_AFTER = "after";

    @RequestMapping("/download")
    public Object queryOffLineData(@RequestParam("userId") String userId, @RequestParam("tenantId") String tenantId) throws BusinessException {
        if(StringUtils.isEmpty(tenantId)){
            tenantId = RuntimeEnvironment.getTenantId();
        }

        if(StringUtils.isEmpty(tenantId)){
            throw new BusinessException("租户ID为空");
        }

        OffLineInvocationContext invocationContext = new OffLineInvocationContext();
        invocationContext.setTenantId(tenantId);
        invocationContext.setUserId(userId);

        Map<String, Object> extensionServiceMap = extendLoader.getExtensionServiceMap();

        // 离线上下文参数扩展
        this.contextExtension(invocationContext, extensionServiceMap);

        Map<String, Object> offLineDataMap = downloadService.queryOffLineData(invocationContext);

        for (Map.Entry<String, Object> entry : offLineDataMap.entrySet()) {
            Object extensionService = extensionServiceMap.get(entry.getKey());
            if (extensionService != null) {
                Method[] methods = extensionService.getClass().getMethods();
                for (Method method : methods) {
                    Offline offline = AnnotationUtils.findAnnotation(method, Offline.class);
                    if (offline != null && OFFLINE_OPERATION_AFTER.equalsIgnoreCase(offline.operate())) {
                        try {
                            Object returnResult = method.invoke(extensionService, entry.getValue());
                            offLineDataMap.put(entry.getKey(), returnResult);
                        } catch (IllegalAccessException | InvocationTargetException e) {
                            String errorInfo = "调用离线数据扩展方法失败：interface[" + extensionService.getClass().getName()
                                    + "], method[" + method.getName() + "], 失败原因：" + e.getMessage();
                            log.error(errorInfo, e);
                            throw new BusinessException(errorInfo);
                        }
                    }
                }
            }
        }

        return offLineDataMap;

    }

    private void contextExtension(OffLineInvocationContext invocationContext, Map<String, Object> extensionServiceMap) throws BusinessException {
        Map<String, Object> extendArguments = invocationContext.getExtendArgumentMap();
        if(extendArguments == null){
            extendArguments = new HashMap<>();
        }

        for (Map.Entry<String, Object> entry : extensionServiceMap.entrySet()) {
            String dataFrom = entry.getKey();
            Object extensionService = entry.getValue();
            Method[] methods = extensionService.getClass().getMethods();
            for (Method method : methods) {
                Offline offline = AnnotationUtils.findAnnotation(method, Offline.class);
                if (offline != null && OFFLINE_OPERATION_BEFORE.equalsIgnoreCase(offline.operate())) {
                    try {
                        Object returnResult = method.invoke(extensionService, invocationContext);
                        extendArguments.put(dataFrom, returnResult);
                    } catch (IllegalAccessException | InvocationTargetException e) {
                        String errorInfo = "调用离线数据扩展方法失败：interface[" + extensionService.getClass().getName()
                                + "], method[" + method.getName() + "], 失败原因：" + e.getMessage();
                        log.error(errorInfo, e);
                        throw new BusinessException(errorInfo);
                    }
                }
            }
        }

        invocationContext.setExtendArgumentMap(extendArguments);
    }
}
